package com.mudrov.primenumbers;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicIntegerArray;

public class PrimeNumbersGetter {
    int limit;
    private AtomicIntegerArray isPrime;
    private double sqrtLim;
    public  PrimeNumbersGetter(int limit){
        this.limit = limit;
        isPrime = new AtomicIntegerArray(limit + 1);
        sqrtLim = Math.sqrt(limit);
    }
    public void executeAtkinBlock(int xBegin, int xLimit) {
        int xQrt = (xBegin-1) * (xBegin - 1);
        for (int x = xBegin; x < xLimit; ++x) {
            xQrt += 2 * x - 1;
            int yQrt = 0;
            for (int y = 1; y <= sqrtLim; ++y) {
                yQrt += 2 * y - 1;
                int n = (xQrt << 2) + yQrt;
                if (n <= limit && (n % 12 == 1 || n % 12 == 5))
                    isPrime.incrementAndGet(n);
                n -= xQrt;
                if (n <= limit && (n % 12 == 7))
                    isPrime.incrementAndGet(n);
                if (x <= y)
                    continue;
                n -= (yQrt << 1);
                if (n <= limit && (n % 12 == 11))
                    isPrime.incrementAndGet(n);
            }
        }
    }
    public void lastPhase() {
        isPrime.getAndSet(1,0);
        isPrime.getAndSet(2,1);
        isPrime.getAndSet(3,1);
        isPrime.getAndSet(5,1);
        for (int i = 2; i <= limit; ++i) {
            if (isPrime.get(i) % 2 == 1) {
                long iQrt = (long)i * (long)i;
                for (long j = iQrt; j <= limit; j += iQrt)
                    isPrime.getAndSet((int)j,0);
            }
        }
    }
    public List<Integer> getSetPrimeNumbers(int startFrom){
        if(startFrom < 0)
            throw new IllegalArgumentException();
        ArrayList<Integer> listOfPrimes = new ArrayList<Integer>();
        for (int i = startFrom; i < isPrime.length(); ++i)
            if (isPrime.get(i) % 2 == 1)
                listOfPrimes.add(i);
        return listOfPrimes;
    }
    public List<Integer> getSetPrimeNumbers(){
        return getSetPrimeNumbers(2);
    }
}
